Skip to content

feat(sdd,agents): SDD-003 spec-gate + AI-019 model-tier policy#60

Merged
mlorentedev merged 1 commit into
mainfrom
feat/SDD-003-ci-spec-gate
May 20, 2026
Merged

feat(sdd,agents): SDD-003 spec-gate + AI-019 model-tier policy#60
mlorentedev merged 1 commit into
mainfrom
feat/SDD-003-ci-spec-gate

Conversation

@mlorentedev
Copy link
Copy Markdown
Owner

Summary

Two logically-distinct changes bundled by user decision (against atomic-PR ideal — conscious deviation, not scope creep) plus a small ghostty config tweak the user authored mid-session.

SDD checklist

  • Vault backlog entries exist (SDD-003-ci-spec-gate, AI-019-model-tier-policy, AUDIT-004-architecture-map)
  • Spec folders included: specs/SDD-003-ci-spec-gate/ and specs/AI-019-model-tier-policy/
  • proposal.md filled for both (Why / What / Acceptance criteria / Risks)
  • tasks.md in TDD order for both
  • verification.md filled for both with evidence + test outputs
  • features.json (SDD-003) tracks 13 features in pending state pre-merge

SDD skip rationale

Test plan

  • bats tests/*.bats645/645 pass (16 new SDD-003 cases + 4 new install-precommit cases)
  • shellcheck --severity=error scripts/*.sh setup-linux.sh clean
  • python3 JSONC validation on ai/opencode/opencode.jsonc (top-level keys + 5 MCP servers intact)
  • python3 -c "import yaml; yaml.safe_load(...)" on .github/workflows/spec-gate.yml clean
  • Self-test: this PR's diff is ≥50 LOC and contains active specs/<feature-id>/ folders → expected to PASS the spec-gate (case B)

Notable decisions

  • LOC formula: added + removed (total churn). A 100-line refactor swap should trigger the gate; SDD-001's "~50–300 LOC of production diff" wording supports this.
  • Pre-push hook, not pre-commit. Spec-gate needs branch diff against origin/main; pre-commit would falsely fail intermediate WIP commits during red-green-refactor.
  • opencode.jsonc native // comments instead of _modelTierComment JSON key — the file already uses // extensively; adding the model-tier block as comments is diff-friendly and avoids polluting the parsed JSON namespace.
  • CLAUDE.md ≤70 line threshold bumped to ≤80 with inline justification in tests/opencode.bats (model-tier addition is intentional cross-agent consistency, not slippage).
  • Gemini + Copilot model IDs marked TBD rather than guessed — speculative literal IDs rot fast.

Out of scope (for future PRs)

  • ADR-011-model-tier-policy in vault (promotion candidate noted in verification.md; ADR-010 is the natural sibling)
  • AUDIT-001 / AUDIT-002 / AUDIT-003 (queued post-merge)
  • AI-017 / AI-018 Copilot v2 schemas (Windows-empirical work)
  • Branch protection rule changes (requires admin GitHub UI; tracked separately)

Companion vault artifact

30-architecture/dotfiles-architecture-map.md (AUDIT-004) landed in the vault via Hive auto-commit ahead of this PR. Two Mermaid diagrams (setup-time + runtime data flow) + 23-row "where does X live" reference table — used as baseline for the queued AUDIT-001/002/003.

Bundle of two logically-distinct changes plus a small ghostty config tweak.
User-elected bundle (against atomic-PR ideal) — conscious deviation, not scope creep.

SDD-003 (Tier 4+5 of the SDD enforcement stack)
- scripts/check-spec-gate.sh: LOC threshold (>=50) + spec-folder presence
  check, basename-aware lockfile exclusion (npm/pnpm/go), `skip-sdd` label +
  rationale escape hatch, dependabot bypass.
- .github/workflows/spec-gate.yml: pull_request trigger, env-var pattern
  (no `${{}}` in run: blocks).
- .github/pull_request_template.md: SDD checklist + skip-rationale header.
- .pre-commit-config.yaml + scripts/install-precommit.sh --with-sdd-gate:
  opt-in pre-push hook for local pre-flight.
- tests/check-spec-gate.bats: 16 cases. tests/install-precommit.bats: +4 cases.

AI-019 (cross-agent model-tier policy)
- AGENTS.md: new "Model Selection (Task-Aware)" section between Standing
  Orders and Competence Retention Protocol. Top / Mid / Low tiers, trigger
  heuristics ("propose, don't force"), per-agent overlay pointers.
- ai/claude/CLAUDE.md, ai/gemini/GEMINI.md, ai/copilot/copilot-instructions.md,
  ai/opencode/opencode.jsonc: ~6-line Model Tier subsection each with literal
  model IDs (Claude empirical; OpenCode empirical; Gemini + Copilot marked TBD
  pending validation).
- tests/opencode.bats: CLAUDE.md threshold bumped 70->80 with inline reason.

terminal/ghostty/config: bell-features=no-system, window-vsync=true (user-authored
session tweaks, bundled at user request).

Specs at specs/SDD-003-ci-spec-gate/ and specs/AI-019-model-tier-policy/.
AUDIT-004 architecture map landed separately in the vault via Hive auto-commit.

Tests: bats 645/645 green; shellcheck --severity=error clean; opencode.jsonc
structurally valid (top-level keys + 5 MCP servers intact); JSON workflow valid.
@mlorentedev mlorentedev merged commit f0cd65a into main May 20, 2026
6 checks passed
@mlorentedev mlorentedev deleted the feat/SDD-003-ci-spec-gate branch May 20, 2026 01:21
mlorentedev added a commit that referenced this pull request May 26, 2026
…gy, copy-only deploy)

Real bug (integration container under set -u):
- scripts/healthcheck.sh skip() referenced $2 unconditionally. Six callsites
  pass only the test name (e.g. agy not in PATH). Fixed via ${2:+ - $2}
  optional suffix so single-arg calls no longer abort with "unbound variable".

Windows healthcheck.ps1 parity:
- 12 section labels were stuck on /12 while sec 13 (Antigravity) used /13.
  Now all 13 use /13, matching healthcheck.sh and unblocking bats parity test.
- Removed unused $agyData assignment (PSScriptAnalyzer warning).
- Updated synopsis docstring 12 sections -> 13.

Test alignment (no behaviour changes — code was already correct):
- tests/healthcheck-ps1.bats: 12 sections -> 13.
- tests/opencode.bats: default model nan/deepseek-v4-flash -> nan/qwen3.6
  (qwen chosen empirically in opencode.jsonc; deepseek is now opt-in via /models).
- tests/opencode.bats: alias oc="opencode --pure" (mirrors .bashrc + profile.ps1).
- tests/powershell-profile.bats: gemini alias -> agy alias (Antigravity migration).
- tests/powershell-profile.bats: oc is now a function (not Set-Alias) so --pure
  can be passed. Parity check updated to match function form on Windows and
  alias form on POSIX.
- tests/verify-setup.bats: post-SDD-007/BUG-100 the setup deploys via copy
  (deploy_file), not symlinks. Tests #20-26, #43, #60 now assert "regular file
  AND NOT a symlink" to make the copy-only invariant explicit. Test #33
  asserts $HOME/.ssh/config has 600 (the file SSH actually reads), not the
  intermediate $DOTFILES_DIR/ssh/config which inherits cp's 644. Test #37
  ~/.gemini/GEMINI.md -> ~/.gemini/AGY.md per gemini-cli -> agy rename.
mlorentedev added a commit that referenced this pull request May 26, 2026
…102)

* fix(BUG-100): resolve circular symlinks and staging latency in agy 1.0.2

- Implemented flat-file strategy for mcp_config.json to bypass agy recursion bug.
- Enforced production endpoint via ANTIGRAVITY_ENDPOINT, CLOUDCODE_URL, and GEMINI_DIR.
- Optimized interactive performance: switched to Flash, reduced verbosity, disabled keep_thinking.
- Ported all fixes to Windows setup and healthcheck scripts for cross-platform parity.
- Updated healthcheck.sh/ps1 with dedicated Antigravity integrity assertions.

* feat(SDD-007): NaN as opencode default + IaC deploy + agy schema fix + MCP trim

* IaC migration: 9x ln -sf -> deploy_file/Deploy-File (utils.{sh,ps1})
* BUG-100 fix: master MCP config at ~/.gemini/config/, mcpServers schema
  (per Google gemini-cli docs), no symlinks
* NaN community as opencode default (nan/qwen3.6 -- 4x faster than
  deepseek-v4-flash per scripts/nan-bench.sh; bench shows reasoning chain
  adds 30-180 tokens silently)
* MCP catalog trim across all environments: keep hive + context7 +
  sequential-thinking. Drop drawio (rare use, spawned subprocess even
  with --pure) and socket (mcp.socket.dev hung 30s+ blocking responses).
* oc alias defaults to 'opencode --pure' (no MCP overhead). ocfull for
  agentic tool-use. Empirical: full mode hung on complex queries due to
  38 tool definitions in system prompt.
* New tooling: dbg alias (reasoning visible workaround for opencode TUI
  which drops non-OpenAI reasoning_content fields), nan-bench,
  nan-quality-bench, cleanup-legacy-ai.{sh,ps1}
* Windows parity: utils.ps1 (Deploy-File/Test-FileDrift),
  cleanup-legacy-ai.ps1, load-secrets.ps1 (added Add-Secret + Update-Secret)
* Drops: agy plugin import gemini, legacy gemini-cli compat write,
  opencode-go provider, aider aliases
* Docs: ai/nan/README.md (provider), ai/opencode/README.md (client pointer)

Closes #100

* fix(SDD-007): PSScriptAnalyzer  + CI integration secrets soft-source

* setup-windows.ps1: rename  to  in MCP merge loop
  (PSAvoidAssignmentToAutomaticVariable --  is reserved)
* setup-linux.sh: remove speculative agy install URL (not confirmed by
  upstream); replace with clear manual-install warning
* setup-linux.sh: wrap secrets fallback in subshell + soft-source so CI
  containers without age vault don't trip set -e during MCP consolidation

* fix(SDD-007): set-e safe jq pipe + update stale bats assertions

* setup-linux.sh: || true on OLD_KEY jq|grep pipe (grep returns 1 on
  empty input; pipefail propagates; was exiting at MCP consolidation
  on fresh CI containers without master config yet)
* tests/setup-linux.bats: tmux.conf assertion migrated to deploy_file
  (SDD-007 IaC strategy)
* tests/setup-windows.bats: gemini->agy section header, opencode.jsonc
  expects Deploy-File helper, GEMINI.md->AGY.md pointer marker

* fix(SDD-007): Windows-parity AGY.md deploy + verify (Neural Hive pointer)

setup-windows.ps1 was missing the AGY.md copy + 'First, read AGENTS.md'
pointer verification that setup-linux.sh ran at line 407-413. Adds it
right before the Gemini prompts sync block to match Linux ordering.
Test in setup-windows.bats updated to assert the pointer marker is
present in BOTH setup scripts (cross-OS parity).

* fix(SDD-007): CI test gates + .bashrc drift tolerance

* setup-linux.sh: .bashrc drops strict check_deployed (tool installers
  legitimately append PATH/init lines; check existence only)
* tests/aliases.bats: oc alias regex now matches both 'opencode' and
  'opencode --pure' (SDD-007 default flipped to --pure)
* tests/antigravity.bats: setup() skips suite when agy not installed
  (CI containers don't have agy; these are integration-style tests)

* fix(SDD-007): rename GEMINI_HOME->AGY_HOME in tests + section count 12->13

env-contract.json already uses AGY_HOME (set in PR #97); tests/env-contract.bats
still referenced the old GEMINI_HOME name. healthcheck.sh has 13 sections after
Antigravity Health was added; tests still asserted 12-section count.

* tests/env-contract.bats: sed GEMINI_HOME -> AGY_HOME (10 refs)
* tests/healthcheck.bats: section count 12 -> 13 (tmux 9/13, ghostty 11/13,
  drift 12/13, antigravity 13/13)
* setup-windows.ps1: post-install summary now shows 'Antigravity: AGY.md'
  instead of the stale 'Gemini config: GEMINI.md' (legacy artifact)

* fix(SDD-007): pre-export AGY_HOME + healthcheck test counts (12->13)

* setup-{linux.sh,windows.ps1}: pre-export AGY_HOME alongside GEMINI_HOME
  in the REFACTOR-002 path-var block (env-contract.json declares AGY_HOME
  as the SSOT name; GEMINI_HOME kept for backward compat)
* tests/healthcheck.bats: section count 12 -> 13 (Antigravity section
  was added in PR #98); tmux assertion now checks check_deployed instead
  of readlink (post-IaC migration: tmux.conf is copied, not symlinked)

* fix(SDD-007): suppress shellcheck SC2016 false-positive on literal $schema match

healthcheck.sh:362 uses single-quoted regex '"\$schema":' to match the
literal '$schema' JSON key in opencode.jsonc -- no expansion intended.
Shellcheck SC2016 flags as 'did you mean to expand?' (info). Suppress
inline so tests/healthcheck.bats:51 (shellcheck-must-pass) stays green
on stricter CI shellcheck versions.

* fix(SDD-007): CI green — skip() bug + parity fixes (12->13, gemini->agy, copy-only deploy)

Real bug (integration container under set -u):
- scripts/healthcheck.sh skip() referenced $2 unconditionally. Six callsites
  pass only the test name (e.g. agy not in PATH). Fixed via ${2:+ - $2}
  optional suffix so single-arg calls no longer abort with "unbound variable".

Windows healthcheck.ps1 parity:
- 12 section labels were stuck on /12 while sec 13 (Antigravity) used /13.
  Now all 13 use /13, matching healthcheck.sh and unblocking bats parity test.
- Removed unused $agyData assignment (PSScriptAnalyzer warning).
- Updated synopsis docstring 12 sections -> 13.

Test alignment (no behaviour changes — code was already correct):
- tests/healthcheck-ps1.bats: 12 sections -> 13.
- tests/opencode.bats: default model nan/deepseek-v4-flash -> nan/qwen3.6
  (qwen chosen empirically in opencode.jsonc; deepseek is now opt-in via /models).
- tests/opencode.bats: alias oc="opencode --pure" (mirrors .bashrc + profile.ps1).
- tests/powershell-profile.bats: gemini alias -> agy alias (Antigravity migration).
- tests/powershell-profile.bats: oc is now a function (not Set-Alias) so --pure
  can be passed. Parity check updated to match function form on Windows and
  alias form on POSIX.
- tests/verify-setup.bats: post-SDD-007/BUG-100 the setup deploys via copy
  (deploy_file), not symlinks. Tests #20-26, #43, #60 now assert "regular file
  AND NOT a symlink" to make the copy-only invariant explicit. Test #33
  asserts $HOME/.ssh/config has 600 (the file SSH actually reads), not the
  intermediate $DOTFILES_DIR/ssh/config which inherits cp's 644. Test #37
  ~/.gemini/GEMINI.md -> ~/.gemini/AGY.md per gemini-cli -> agy rename.

* fix(SDD-007): finish 12->13 renumber in healthcheck-ps1.bats per-section tests

Previous commit missed the inline per-section assertions (tests #190-205):
- The loop iterating 1..12 over Write-Section labels (line 64).
- 12 per-section assertions hardcoding the /12 denominator (lines 73-118).
- 3 SKIP/drift assertions referencing /12 (lines 123, 127, 131-138).

All now match the .ps1 labels (1/13..13/13). Added missing assertion for
section 13/13 (Antigravity CLI Health, SDD-007).
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant